﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
using System.Drawing.Design;
using System.Windows.Forms.Design;

namespace UtfprLibrary.Windows.Forms.ComponentModel {
    /// <summary>
    /// TODO
    /// </summary>
    internal class UBNValidatableControlCollectionEditor : UITypeEditor {
        private ITypeDescriptorContext _context = null;
        private IServiceProvider _provider = null;
        private object value = null;

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
            return UITypeEditorEditStyle.Modal;
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="context"></param>
        /// <param name="provider"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
            if (context != null && provider != null) {
                this._context = context;
                this._provider = provider;
                this.value = value;
                var result = showEditorDialog();
                if (result.IsDialogResultOK) {
                    value = result.Value;
                }
            }
            return value;
        }

        /// <summary>
        /// No special thumbnail will be shown for the grid.
        /// </summary>
        public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context) {
            return false;
        }

        #region Private Methods

        private UBNValidatableControlCollection getValidatableControls() {
            //coleção que armazenará a coleção de controles do formulário que está associado ao componente
            var validatableControls = new UBNValidatableControlCollection();

            try {
                var validator = (UBNRequiredFieldsValidatorBase)_context.Instance;

                if (validator.UtfprBindingNavigator != null) {
                    //carrega a coleção de controles do formulário que está associado ao componente
                    foreach (Control c in _context.Container.Components.OfType<Control>()) {
                        try {
                            if (c is TextBox || c is MaskedTextBox) {
                                if (c.DataBindings["Text"].DataSource == validator.UtfprBindingNavigator.DataSource) {
                                    validatableControls.Add(new UtfprValidatableControl(c, UtfprWindowsFormsConsts.UBNValidatableControlCollectionEditor_Validator_ErrorMessage));
                                }
                            } else if (c is ComboBox) {
                                if ((c as ComboBox).DataSource == validator.UtfprBindingNavigator.DataSource) {
                                    validatableControls.Add(new UtfprValidatableControl(c, UtfprWindowsFormsConsts.UBNValidatableControlCollectionEditor_Validator_ErrorMessage));
                                }
                            } else if (c is UtfprDateTimePickerBase) {
                                if (c.DataBindings["Value"].DataSource == validator.UtfprBindingNavigator.DataSource) {
                                    validatableControls.Add(new UtfprValidatableControl(c, UtfprWindowsFormsConsts.UBNValidatableControlCollectionEditor_Validator_ErrorMessage));
                                }
                            } else  if (c is UtfprGroupBoxBase) {
                                if (c.DataBindings["ValueField"].DataSource == validator.UtfprBindingNavigator.DataSource) {
                                    validatableControls.Add(new UtfprValidatableControl(c, UtfprWindowsFormsConsts.UBNValidatableControlCollectionEditor_Validator_ErrorMessage));
                                }                            
                            } else if (c is UtfprLookupFieldBase) {
                                if ((c as UtfprLookupFieldBase).LookupSource == validator.UtfprBindingNavigator.DataSource) {
                                    validatableControls.Add(new UtfprValidatableControl(c, UtfprWindowsFormsConsts.UBNValidatableControlCollectionEditor_Validator_ErrorMessage));
                                }                            
                            }
                        } catch { }
                    }
                }
            } catch { }

            return validatableControls;
        }

        private void fillEditor(UtfprFormValidatableControlCollectionEditor dialog) {
            try {
                var validatableControls = getValidatableControls();
                var sourceControls = value as UBNValidatableControlCollection;
                if (sourceControls != null) {
                    //se não existir nenhum controle associado
                    if (sourceControls.Count == 0) {
                        //carregue todos os controles do container na
                        //coleção do formulário de edição
                        dialog.SourceCollection = validatableControls;
                    } else {
                        foreach (UtfprValidatableControl c in validatableControls) {
                            //verifique se o componente possui o controle
                            if (sourceControls.ContainsControl(c.Control)) {
                                //insira o controle na coleção de controles marcados para validação
                                int index = sourceControls.GetItemIndex(c.Control);
                                dialog.ValidatableCollection.Add(sourceControls[index]);
                            } else {
                                //insira o controle na coleção de controles que ainda não foram marcados para validação
                                dialog.SourceCollection.Add(c);
                            }
                        }
                    }
                }
            } catch { }
        }

        private void updateComponent(UBNValidatableControlCollection sourceCollection, UBNValidatableControlCollection validatableCollection) {
            try {
                var sourceControls = value as UBNValidatableControlCollection;
                if (sourceControls != null) {
                    //marca o componente para mudança
                    _context.OnComponentChanging();

                    //remove todos os componentes que foram desmarcados para validação
                    foreach (UtfprValidatableControl c in sourceCollection) {
                        if (sourceControls.GetItemIndex(c.Control) != -1) {
                            int index = sourceControls.GetItemIndex(c.Control);
                            sourceControls.RemoveAt(index);
                        }
                    }

                    //adiciona todos os componentes que foram marcados para validação
                    foreach (UtfprValidatableControl c in validatableCollection) {
                        if (!sourceControls.ContainsControl(c.Control)) {
                            sourceControls.Add(c);
                        }
                    }

                    //comita as mudanças efetuadas
                    _context.OnComponentChanged();
                }
            } catch { }
        }

        /// <summary>
        /// Show a UtfprFormPickerEditor dialog, retrieving the result value.
        /// </summary>
        private UtfprFormResult showEditorDialog() {
            UtfprFormResult result = new UtfprFormResult();
            result.IsDialogResultOK = false;
            try {
                IWindowsFormsEditorService editorService = _provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;
                if (editorService != null) {
                    var editor = new UtfprFormValidatableControlCollectionEditor();
                    fillEditor(editor);

                    //guarda as referências do formulário de diálogo, pois elas
                    //são destruidas assim que o formulário é fechado
                    var sourceCollection = editor.SourceCollection;
                    var validatableCollection = editor.ValidatableCollection;

                    if (editorService.ShowDialog(editor) == DialogResult.OK) {
                        result.IsDialogResultOK = true;
                        updateComponent(sourceCollection, validatableCollection);
                        result.Value = value;
                    }
                }
            } catch { }
            return result;
        }

        #endregion
    }
}
